The blog of dlaa.me

Posts tagged "WPF Toolkit"

My new home page, rejuvenated [Updated collection of great Silverlight/WPF/Windows Phone Data Visualization resources!]

It's been a few months since I posted my previous collection of Silverlight/WPF Charting links. In the meantime, the April 2010 release of the Silverlight Toolkit was published with support for stacked series and significant performance improvements! And Windows Phone 7 has been steadily building momentum - it's handy that the Data Visualization assembly also works on Windows Phone!

So there's lots of good stuff - here are all the links (FYI: previously published links are gray):

Overviews (100 level)

Scenarios (200 level)

Internals (300 level)

Team Member posts (Partner level)

My posts (Ego level)

Many thanks go out to everyone who has spent time helping people learn how to use Silverlight/WPF/Windows Phone Data Visualization!

PS - If I've missed something useful, please send me a link - I'm always happy to find more great content! :)

PPS - The most recent version of this collection will always be pointed to by http://cesso.org/r/DVLinks. If you're going to create a favorite or link to this post, please use that URL so your link will always be current.

Please rate your dining experience [How to: Show text labels on a numeric axis with Silverlight/WPF Toolkit Charting]

A customer contacted me a few days ago asking how to display text labels on a NumericAxis. (Whereas CategoryAxis makes it easy to use text labels for the independent axis, this request was about text labels on the dependent axis.) It's a bit of an unusual request (I spent a minute just now and don't see how to accomplish this in Excel), but I knew it would be easy to do with the Charting controls in the Data Visualization assembly that's part of the Silverlight Toolkit and WPF Toolkit.

The underlying scenario is to provide labels for the results of one of those "How are we doing?" surveys restaurants and hotels like to give out. The chart should look like this:

Text labels on the dependent axis

Though I originally suggested a different approach, the act of coding it up myself suggested a trusty old IValueConverter would be most appropriate. (Aside: See more IValueConverter tricks here and here.) The basic approach is to explicitly specify the dependent axis and then use it to configure exactly the set of tick marks we want. Once that's done, a simple bit of IValueConverter magic converts the numeric values into their corresponding text labels - and the problem is solved! :)

 

I've added the sample shown here to my DataVisualizationDemos application which is collection of all the Data Visualization samples I've blogged. Like the core Data Visualization code itself, the demo app compiles for and runs on multiple platforms with the same code and XAML - it's an easy way to publish a sample and show it running on Silverlight 3, Silverlight 4, WPF 3.5, and WPF 4. Just for kicks, I've used the "Compatible" ColumnSeries for this example - but it works just as well with traditional ColumnSeries. Better yet, the basic idea can be generalized to solve a variety of similar problems as well!

 

[Click here to download the complete source code for the cross-platform DataVisualizationDemos sample application. ]

 

Here's the relevant XAML:

<!-- Chart of customer feedback -->
<charting:Chart Title="Customer Feedback">
    <compatible:ColumnSeries
        ItemsSource="{Binding}"
        IndependentValuePath="Topic"
        DependentValuePath="Rating">

        <!-- Custom Y axis for text labels -->
        <compatible:ColumnSeries.DependentRangeAxis>
            <charting:LinearAxis
                Orientation="Y"
                Minimum="0"
                Maximum="4"
                Interval="1"
                ShowGridLines="True">

                <!-- Custom style/template for text labels -->
                <charting:LinearAxis.AxisLabelStyle>
                    <Style TargetType="charting:AxisLabel">
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="charting:AxisLabel">
                                    <TextBlock Text="{Binding Converter={StaticResource RatingToStringConverter}}"/>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </charting:LinearAxis.AxisLabelStyle>
            </charting:LinearAxis>
        </compatible:ColumnSeries.DependentRangeAxis>

        <!-- Custom style for different background -->
        <compatible:ColumnSeries.DataPointStyle>
            <Style TargetType="charting:DataPoint">
                <Setter Property="Background" Value="#ff00a0e0"/>
            </Style>
        </compatible:ColumnSeries.DataPointStyle>
    </compatible:ColumnSeries>
</charting:Chart>

And code:

/// <summary>
/// Implements IValueConverter to convert from double rating values to friendly string names.
/// </summary>
public class RatingToStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        // Validate parameters
        if (!(value is double))
        {
            throw new NotSupportedException("Unsupported value type in RatingToStringConverter.");
        }
        // Convert number to string
        double doubleValue = Math.Floor((double)value);
        if (0.0 == doubleValue)
        {
            return "Awful";
        }
        else if (1.0 == doubleValue)
        {
            return "Poor";
        }
        else if (2.0 == doubleValue)
        {
            return "Fair";
        }
        else if (3.0 == doubleValue)
        {
            return "Good";
        }
        else if (4.0 == doubleValue)
        {
            return "Great";
        }
        else
        {
            throw new ArgumentException("Unsupported value in RatingToStringConverter.");
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Nobody likes a show-off [Today's DataVisualizationDemos release includes new demos showing off stacked series behavior]

My DataVisualizationDemos application is a collection of nearly all the Data Visualization samples I've posted to my blog. And just like the Data Visualization assembly (get Silverlight/WPF Data Visualization Development Release 4 here!), the demo application runs on Silverlight 3, Silverlight 4, WPF 3.5, and WPF 4 and shares the same code and XAML across all platforms. It's a handy way to look at bunch of sample code running on any of the supported platforms. What's more, each demo page has hyperlinks to relevant blog post(s) for more detail about each scenario, so it's a good learning tool as well! :)

 

Click here to download the complete source code for the cross-platform DataVisualizationDemos sample application.

 

Stacked Series demo

Of the two completely new demos, the prettiest is definitely the "Stacked Series" sample shown above. Its interface is simple - you choose one to three sets of stacked data for examples of all four stacking types and can control the nature of that data: positive/mixed/negative small/large ints/doubles. As you might guess, the corresponding value changes are fully animated, so it's pleasing to watch the charts flow from one configuration to another.

There's also a check-box for switching the examples from "normal" stacked mode into "100%" stacked mode. This transition is not animated because what goes on behind the scenes is a swap of the series types in use. Similarly, choosing a different kind of independent value from the combo-box (string, consecutive numbers, random numbers, or dates) re-creates the data and is not animated.

Disclaimer: As soon as you start playing around with negative values, you'll think you've found a bad rendering bug. But before you fire off an email telling me what a bone-head I am for getting things wrong, please finish reading this post... :)

 

Text-To-Chart demo

The less attractive - but arguably more interesting - of the two new demos is the "Text-To-Chart" sample shown above. What it lacks in sophisticated UI polish, it makes up for in flexibility. The idea is that you (or me when I'm testing things!) can paste simple tabular data directly from Excel and see how it looks in any of the eight new stacked series types. The dependent values of a single series go down and different series go across (using tab, space, or ';' as a delimiter). It's flexible, so you can have any number of dependent values or series! Independent values are generated automatically according to row number; the only requirement is that every row needs to have the same number of values (i.e., no missing data). If everything checks out, you get a pretty chart of the data - if not, the text turns red to indicate a problem that needs to be corrected.

After a little while playing around with negative numbers, you might end up with the chart shown below;

Stacked area series with negative values - TextToChart

Clearly, this is a rendering bug - that can't possibly be correct! Let's try it in Excel to see how it's supposed to look so we can tell the developer what a complete bone-head he is:

Stacked area series with negative values - Excel

Oh, snap, it's not a bug after all! :) Whereas the behavior of stacked bar and column charts is fairly intuitively obvious in the presence of negative values, the behavior of stacked line and area charts is not. But it turns out that Excel implements a fairly simple algorithm here - and once I stared at things long enough to figure out what it was, my stacked series charts suddenly matched Excel in all the weird scenarios I've tried so far.

Of course, that's not to say there aren't still bugs in the stacked series implementation - there are bound to be because everything has bugs. But the good news is that I may not be a total bone-head after all. That said, if you run into a scenario where the output from the stacked series code differs from that of Excel, I'd love to hear about it - and "Text-To-Chart" provides a really easy way of sending a bug report! :)

 

Performance Tweaks with a Compatible series

The last thing I wanted to call out is that I've updated the "Performance Tweaks" sample (above) to allow the creation of a "Compatible" ScatterSeries (shown above) in addition to the normal kind. You can read more about what I mean in my detailed discussion of the new stacked series support. What's important to know is that holding down the Ctrl key switches the "Add Series" button to an "Add Compatible Series" button - and the resulting series name in the legend will be "Standard" or "Compatible" accordingly.

This makes it easy to see some of the performance improvements I discuss in that blog post for yourself. One good example is the following: Reset, Create Chart, Add Series, Populate, [watch as the points fade in], Change Values, [watch as they move], Change Values, etc.. Now repeat those same steps with a Compatible series and note how everything runs faster!

Aside: If you're on WPF, you may need to increase the number of points before you start seeing a difference.

 

And there you have it: cool new samples to go with the new Data Visualization features. The DataVisualizationDemos application is one of my favorite test cases because it implements a bunch of different scenarios with a variety of different techniques and it runs everywhere the Data Visualization assembly does. (Or at least it did until Windows Phone 7 showed up... Hum, maybe I'll port to that platform next time...)

DataVisualizationDemos has been a tremendous help for me and I hope you enjoy it, too!

Phone-y charts [Silverlight/WPF Data Visualization Development Release 4 and Windows Phone 7 Charting sample!]

The April '10 release of the Silverlight Toolkit brought stacked series support to the Data Visualization assembly on the Silverlight 4 platform! You can read an overview here and get a detailed description here. Almost simultaneously, the WPF team released WPF 4 as part of .NET 4 and Visual Studio 2010.

So it's time for an updated version of my Silverlight/WPF Data Visualization Development Release. Like the previous version, this one continues to support the four platforms of interest to most .NET developers: Silverlight 3, Silverlight 4, WPF 3.5, and WPF 4. But what about Windows Phone 7, the new fifth platform for .NET developers? Yeah, it's supported, too! :)

 

Silverlight/WPF Data Visualization Development Release 4

As with previous Data Visualization Development Releases, I've updated the code and binaries to match the most recent Toolkit release. The Silverlight 4 Toolkit shipped most recently, so the code in this Development Release is identical to what just went out with that. Which means people using Data Visualization on Silverlight 3, Windows Phone 7, WPF 3.5, or WPF 4 can also take advantage of the latest round of improvements by updating their applications to use the binaries included with this Development Release (or by compiling the included source code themselves).

Notes:

  • The directions for using this release are the same as last time, so please have a look at earlier posts if you're new to this or need a refresher.
  • It's easy to use Data Visualization on Windows Phone 7: simply add a reference to the pre-compiled System.Windows.Controls.DataVisualization.Toolkit.dll assembly from this Development Release and a reference to the System.Windows.Controls.dll assembly from the Silverlight 3 SDK (it contains the implementation of Legend's base class HeaderedItemsControl). Then write the same code/XAML you would for any of the other platforms - it's all interchangeable!
    Aside: The version of Silverlight used by Windows Phone 7 is conceptually equivalent to Silverlight 3 with a variety of Silverlight 4 enhancements throughout.
  • All the same cross-platform shared code/XAML goodness of previous Development Releases still applies.

[Click here to download the SilverlightWpfDataVisualization solution including complete source code and pre-compiled binaries for all platforms.]

 

Windows Phone 7 Data Visualization Sample

Trying to use the November 2009 version of the Data Visualization assembly on Windows Phone 7 doesn't work because there's a bug in the Phone version of the .NET Framework that causes bogus exceptions. That bug will be fixed in a future drop of Windows Phone 7 developer bits, but for now it was simplest to work around it myself so folks could start playing around with Data Visualization on the phone today. I wrote the sample application below to show that the Silverlight 3 version of Data Visualization now works seamlessly on Windows Phone 7. And while I was at it, I went ahead and customized the default UI a bit (mostly just tweaking colors and backgrounds) so things really fit in with the overall look and feel of the platform:

Sample in portrait orientation

As part of this, I made some trivial Template customizations for the Chart element and added just a smidge of code to switch Templates when the device orientation changes. This allows the sample application to make better use of the available screen space (note how the Legend moves and changes shape):

Sample in landscape orientation

Notes:

  • Please be sure to open MainPage.xaml in the development environment before hitting F5 to run the sample - otherwise it seems that deployment of the application to the emulator fails with the message "Object reference not set to an instance of an object.".
  • For convenience, I've included the two required assemblies in the ZIP for the sample - all you need in order to build and run is the Windows Phone Developer Tools CTP which can be downloaded for free here.
  • Though this is hardly the most interesting chart ever, I hope some of what I show here inspires others to achieve greater things! :)

 

[Click here to download the complete Windows Phone 7 Data Visualization sample application.]

My new home page, refreshed [Updated collection of great Silverlight/WPF Data Visualization resources!]

Some great content has been published since I posted my previous collection of Silverlight/WPF Charting links. What's more, the November 2009 release of the Silverlight Toolkit and the February 2010 release of the WPF Toolkit have both been released, so please have a look at them if you haven't already!

Now, without further ado, here are all links that are fit to print (FYI: previously published links are gray):

Overviews (100 level)

Scenarios (200 level)

Internals (300 level)

Team Member posts (Partner level)

My posts (Ego level)

My many thanks go out to everyone who has spent time helping people learn how to use Silverlight/WPF Data Visualization!

PS - If I've missed any good resources, please leave a comment with a link - I'm always happy to find more great content! :)

PPS - The most recent version of this collection will always be pointed to by http://cesso.org/r/DVLinks. If you're going to create a favorite or link to this post, please use that URL so you'll always be up to date.

Turn your head and check out this post [How to: Easily rotate the axis labels of a Silverlight/WPF Toolkit chart]

When someone asked me how to rotate the axis labels of a chart from the Data Visualization package of the Silverlight Toolkit/WPF Toolkit earlier today, I realized it was time for a quick blog post. Because when I've answered a question two or three times, it's usually a pretty good sign that I'll keep on answering it for some time. I usually try to head that kind of thing off at the pass, so here's my post on the topic for the benefit of future generations. :)

The typical scenario here is that someone has a chart and it's working well, but their axis labels are very long and end up overlapping - even after the default axis behavior of putting them in alternating rows to prevent such a problem kicks in:

Overlapping axis labels

 

The typical solution is to rotate the axis labels - and it's easy once you know where to look. The key here is to customize the Template of the AxisLabel instances that are used to render the labels. And it's quite simple to do so by providing a Style with a Template Setter for the AxisLabelStyle property of the Axis subclass in question:

Rotated axis labels on WPF

Yeah, it looks great on paper; but that description was a mouthful...

It's probably easier to understand in XAML - here's the complete code for the sample above with the interesting part highlighted:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:charting="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:spec="clr-namespace:System.Collections.Specialized;assembly=System"
        Title="RotatedAxisLabelsWPF"
        Width="500"
        Height="350">
    <Grid>
        <charting:Chart
            Title="Animals With Long Names">
            <charting:ColumnSeries
                Title="Character count"
                DependentValueBinding="{Binding Length}"
                IndependentValueBinding="{Binding}">
                <charting:ColumnSeries.ItemsSource>
                    <spec:StringCollection>
                        <sys:String>Bumblebee</sys:String>
                        <sys:String>Caterpillar</sys:String>
                        <sys:String>Hippopotamus</sys:String>
                        <sys:String>Rhinoceros</sys:String>
                        <sys:String>Velociraptor</sys:String>
                    </spec:StringCollection>
                </charting:ColumnSeries.ItemsSource>
                <charting:ColumnSeries.IndependentAxis>
                    <charting:CategoryAxis
                        Orientation="X">
                        <charting:CategoryAxis.AxisLabelStyle>
                            <Style TargetType="charting:AxisLabel">
                                <Setter Property="Template">
                                    <Setter.Value>
                                        <ControlTemplate TargetType="charting:AxisLabel">
                                            <TextBlock Text="{TemplateBinding FormattedContent}">
                                                <TextBlock.LayoutTransform>
                                                    <RotateTransform Angle="-60"/>
                                                </TextBlock.LayoutTransform>
                                            </TextBlock>
                                        </ControlTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Style>
                        </charting:CategoryAxis.AxisLabelStyle>
                    </charting:CategoryAxis>
                </charting:ColumnSeries.IndependentAxis>
            </charting:ColumnSeries>
        </charting:Chart>
    </Grid>
</Window>

Like I said, it's all pretty standard stuff once you know where to look. Of course, you can rotate the labels all the way to 90 degrees if you want them to take the least amount of space possible. But 60 degrees seemed like a suitably rakish angle. ;)

 

Unfortunately, we can't declare "Mission Accomplished" quite yet... While the Data Visualization assembly itself works exactly the same on WPF and Silverlight, the platforms themselves aren't identical quite yet. Specifically, there's no support for LayoutTransform in Silverlight (and RenderTransform is simply not appropriate here). Fortunately, I've filled the LayoutTransform gap with my LayoutTransformer class - and it's already part of the Silverlight Toolkit!

The syntax changes just a bit, but the concept is exactly the same:

<UserControl x:Class="SilverlightApplication1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:charting="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"
    xmlns:layout="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit">
    <Grid>
        <charting:Chart
            Title="Animals With Long Names">
            <charting:ColumnSeries
                Title="Character count"
                DependentValueBinding="{Binding Length}"
                IndependentValueBinding="{Binding}">
                <charting:ColumnSeries.ItemsSource>
                    <toolkit:ObjectCollection>
                        <sys:String>Bumblebee</sys:String>
                        <sys:String>Caterpillar</sys:String>
                        <sys:String>Hippopotamus</sys:String>
                        <sys:String>Rhinoceros</sys:String>
                        <sys:String>Velociraptor</sys:String>
                    </toolkit:ObjectCollection>
                </charting:ColumnSeries.ItemsSource>
                <charting:ColumnSeries.IndependentAxis>
                    <charting:CategoryAxis
                        Orientation="X">
                        <charting:CategoryAxis.AxisLabelStyle>
                            <Style TargetType="charting:AxisLabel">
                                <Setter Property="Template">
                                    <Setter.Value>
                                        <ControlTemplate TargetType="charting:AxisLabel">
                                            <layout:LayoutTransformer>
                                                <layout:LayoutTransformer.LayoutTransform>
                                                    <RotateTransform Angle="-60"/>
                                                </layout:LayoutTransformer.LayoutTransform>
                                                <TextBlock Text="{TemplateBinding FormattedContent}"/>
                                            </layout:LayoutTransformer>
                                        </ControlTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Style>
                        </charting:CategoryAxis.AxisLabelStyle>
                    </charting:CategoryAxis>
                </charting:ColumnSeries.IndependentAxis>
            </charting:ColumnSeries>
        </charting:Chart>
    </Grid>
</UserControl>

Mission accomplished:

Rotated axis labels on Silverlight

 

There you have it: AxisLabelStyle is your new best friend. A friend with benefits, one might say, because there are other cool things you can do by customizing the AxisLabel Style.

So please: go forth and enjoy your new friend!

This is what happens when two Toolkits fall in love... [The February 2010 release of the WPF Toolkit is now available!]

The WPF Toolkit team has just published the February 2010 release of the WPF Toolkit! In addition to a variety of bug fixes for DataGrid, DatePicker, Calendar, and Visual State Manager, this release also includes the latest changes to the Data Visualization assembly for Silverlight and WPF, bringing the official WPF implementation up to date with the November 2009 release of the Silverlight Toolkit. And because sharing the Silverlight Toolkit's Data Visualization assembly with WPF Toolkit customers has worked out so well, this release of the WPF Toolkit introduces three other controls from the Silverlight Toolkit: AutoCompleteBox (SDK documentation), Accordion, and Rating!

 

WPF Toolkit February 2010 installer

 

Just as with the Data Visualization assembly, the WPF Toolkit implementation of AutoCompleteBox, Accordion, and Rating are almost identical copies of the latest Silverlight Toolkit implementations - we've even kept the same assembly names and structure. Therefore, everything you already know and love about these controls on Silverlight (including your code and XAML) should translate seamlessly to WPF! Even the Visual Studio 2008 design-time experience for these controls should be the same; we've brought the Visual Studio design-time assemblies over, too!

These controls have been part of the Silverlight Toolkit long enough that there are plenty of great resources on the web for information, examples, and more. I expect WPF developers will come up to speed quickly and be able to start taking advantage of them in WPF applications in no time! :)

 

Aside: This release of the WPF Toolkit targets the version of WPF that is part of .NET 3.5 (just as previous releases did). There isn't a version of the WPF Toolkit specifically for .NET 4 - largely because many of the controls in the WPF Toolkit were folded into WPF 4 itself!

 

Those of you who follow the progress of the Data Visualization project already know that I maintain a collection of helpful links from all over the web here: http://cesso.org/r/DVLinks. Another handy resource for new users is my DataVisualizationDemos sample project which runs on Silverlight 3, Silverlight 4, WPF 3.5, and WPF 4 and provides examples of a bunch of different things made possible by the Data Visualization project. Finally, there are some WPF Toolkit-specific notes that are part of my WPF Toolkit June 2009 announcement and which may be worth reviewing. (In particular, the "Build Notes" section covers an issue that occasionally trips people up when trying to compile the design-time assemblies themselves.)

 

Release notes: For a summary of the changes to the WPF version of Data Visualization since the June 2009 WPF Toolkit and numerous code/XAML examples, please have a look at my announcements for the July 2009, October 2009, and November 2009 releases of the Silverlight Toolkit.

 

It's always exciting when there's a new Toolkit release - and a bit of a relief because there's a lot of work that goes on behind the scenes to make these possible. I'd like to thank the WPF Toolkit team for their continued support of Data Visualization and for their willingness to include additional controls from the Silverlight Toolkit. In particular, I'd like to thank Patrick Danino who did nearly all the work to port the three new controls over to WPF, test them, and resolve a few platform incompatibilities that came up! His efforts went well beyond what I expected when he and I first talked about the idea and it has been a pleasure working with him on this. If any bugs happened to sneak through, it's not for lack of effort on Patrick's part. :) Please don't blame him - blame me instead!

Sometimes it takes a village to solve a problem [Workaround for a Visual Studio 2008 design-time issue with the WPF Toolkit when Blend 3 is installed]

Back in June, the "WPF" half of Silverlight/WPF Charting made its first official appearance with the release of the June 2009 WPF Toolkit. Having Charting be part of both the Silverlight Toolkit and the WPF Toolkit was always a goal of mine and I've heard from lots of customers who are using Charting with great success on WPF. By and large, everyone's feedback has been positive and the community enthusiasm has been fantastic to see!

Unfortunately there's one problem that's come up a few times which nobody really had enough context to solve. A user with Visual Studio 2008 and the June 2009 WPF Toolkit installed would be happily using the Data Visualization assembly (Charting) in their projects and everything would be working fine for weeks on end. Then one day they'd install Blend 3 and all of a sudden Visual Studio 2008 would fail trying to open the Charting project with a confusing "Problem Loading" error from the design surface:

'/Microsoft.Windows.Design.Developer;component/themes/GridAdorners.xaml' value cannot be assigned to property 'Source' of object 'System.Windows.ResourceDictionary'. Cannot create instance of 'GenericTheme' defined in assembly 'Microsoft.Windows.Design.Interaction, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Exception has been thrown by the target of an invocation.

The first thing most people would try is uninstalling Blend 3 - which fortunately "fixes" the problem - but makes for a crummy long-term solution...

Fortunately, we managed to get the right people from the Silverlight Toolkit, Blend 3, and Visual Studio 2008 teams in a room a few days ago to hash this out. The first bit of good news is that we did sort out enough of what's going on to come up with an easy workaround. The second bit of good news is that I've already made a change to the WPF Toolkit source code so the next official release won't trigger this problem. And the third bit of good news is that they're going to make sure the underlying issue is addressed in Visual Studio 2010 so this doesn't come up again!

Here's the official synopsis of the problem and the steps to implement the simple workaround:

Known Issue with WPF Toolkit June 2009, Visual Studio 2008, and Blend 3

If a customer has Visual Studio 2008, WPF Toolkit June 2009, and Blend 3 installed, and the WPF project in Visual Studio 2008 has a reference to System.Windows.Controls.DataVisualization.Toolkit.dll, you may see the following error message when opening the project or loading the designer:

Error 1 '/Microsoft.Windows.Design.Developer;component/themes/GridAdorners.xaml' value cannot be assigned to property 'Source' of object 'System.Windows.ResourceDictionary'. Cannot create instance of 'GenericTheme' defined in assembly 'Microsoft.Windows.Design.Interaction, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Exception has been thrown by the target of an invocation. Error at object 'ResourceDictionary_4'.

The problem can be triggered by dragging the Chart control from WPF Toolkit June 2009 from the Toolbox onto the WPF designer in Visual Studio.

To resolve this issue, use the following workaround:

From an account with elevated/administrative permissions, in the WPF Toolkit June 2009 install directory on the machine (typically "C:\Program Files\WPF Toolkit\v3.5.40619.1"):

  1. Rename System.Windows.Controls.DataVisualization.Toolkit.Design.dll to System.Windows.Controls.DataVisualization.Toolkit.Design.4.0.dll
  2. Rename System.Windows.Controls.DataVisualization.Toolkit.Design.pdb to System.Windows.Controls.DataVisualization.Toolkit.Design.4.0.pdb

Thank you for everyone's patience as we sorted this out. I wish we could have done so sooner, but I'm really glad we seem to have gotten to the bottom of it at last!

 

PS - If you still have problems after applying the fix, please let us know!

"I feel the need... the need for SPEED!" [Seven simple, performance-boosting tweaks for common Silverlight/WPF Charting scenarios]

No matter how fast things are, they never seem to be fast enough. Even if we had the world's most optimized code in the Silverlight/WPF Data Visualization assembly, I bet there would still be a couple of people who wanted better performance. :) Unfortunately, we have don't have the world's most optimized code, and performance concerns represent one of the most common customer issues with Charting. While I wish we had the resources to commit to a few weeks of focused performance work, things just haven't panned out like that so far.

Instead, I've got the next best thing: a collection of simple changes anyone can make to noticeably improve the performance of common scenarios with today's bits! To demonstrate the impact of each of these tips, I've created a new "Performance Tweaks" tab in my DataVisualizationDemos sample application. The controls on this new page let you pick-and-choose which optimizations you'd like to see - then allow you to run simple scenarios to get a feel for how effective those tweaks are. And because DataVisualizationDemos compiles for and runs on Silverlight 3, Silverlight 4, WPF 3.5, and WPF 4, it's easy to get a feel for how much benefit you can expect to see on any supported platform.

For each of the seven tips below, I list simple steps that show the performance benefit of the tip using the new sample page. Performance improvements are best experienced in person, so I encourage interested readers to download the demo and follow along at home! :)

 

[Click here to download the complete source code for the cross-platform DataVisualizationDemos sample application.]

 

Performance Tweaks Demo

 

Tip: Use fewer data points

Okay, this first tip is really obvious - but it's still valid! Fewer data points means less to process, less to manage, and less to render - all of which mean that scenarios with few points to tend to be faster and smoother than those with many points. You can often reduce the number of points in a scenario by plotting fewer values, aggregating similar values together, or by showing subsets of the whole data. This approach isn't always practical, but when it is, it's usually a big win - and has the added benefit that the resulting chart is less cluttered and can even be easier to understand!

Aside: Typical performance guidance for Silverlight and WPF recommends capping the total number of UI elements in the low- to mid-hundreds. Given that each of Charting's DataPoint instances instantiates around 5 UI elements, it's easy to see why rendering a chart with 1000 data points can start to bog the system down.

Slow: Reset, check only Simplified Template, Create Chart, Add Series, 1000 points, Populate

Fast: Reset, check only Simplified Template, Create Chart, Add Series, 50 points, Populate

 

Tip: Turn off the fade in/out VSM animations

By default, data points fade in and fade out over the period of a half second. This fade is controlled by a Visual State Manager state transition in the usual manner and therefore each DataPoint instance runs its own private animation. When there are lots of data points coming and going, the overhead of all these parallel animations can start to slow things down. Fortunately, the DataPoint classes are already written to handle missing states, so getting rid of these animations is a simple matter of modifying the default Template to remove the "RevealStates"/"Shown" and/or "RevealStates"/"Hidden" states.

Slow: Reset, uncheck everything, Create Chart, Add Series, 100 points, Populate

Fast: Reset, check only No VSM Transition, Create Chart, Add Series, 100 points, Populate

 

Tip: Change to a simpler DataPoint Template

I mentioned above that overwhelming the framework with lots of UI elements can slow things down. So in cases where it's not possible to display fewer points, it's still possible to display fewer elements by creating a custom Template that's simpler than the default. There is a lot of room here to creatively balance simplicity (speed) and visual appeal (attractiveness) here, but for the purposes of my demonstration, I've gone with something that's about as simple as it gets:

<Style x:Key="SimplifiedTemplate" TargetType="charting:ScatterDataPoint">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="charting:ScatterDataPoint">
                <Grid
                    Width="5"
                    Height="5"
                    Background="{TemplateBinding Background}"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
Aside: This tip and the previous one are the only two tips that are mutually exclusive (because they both involve providing a custom DataPointStyle for the series). Otherwise, you have complete freedom to mix-and-match whatever tweaks work well for your scenario!

Slow: Reset, uncheck everything, Create Chart, Add Series, 100 points, Populate

Fast: Reset, check only Simplified Template, Create Chart, Add Series, 100 points, Populate

 

Tip: Specify fixed ranges for the axes

For convenience and ease-of-use, Charting's axes automatically analyze the data that's present in order to provide reasonable default values for their minimum, maximum, and interval. This works quite well in practice and you should hardly ever have to override the automatic range. However, the code that determines the automatic axis ranges isn't free. This cost isn't significant for static data, but if the underlying values are changing a lot, the small cost can accumulate and become noticeable. If you're fortunate enough to know the ranges over which your data will vary, explicitly specifying the axes and giving them fixed ranges will completely eliminate this overhead.

Slow: Silverlight 3, Reset, uncheck everything, Create Chart, Add Series, 100 points, Populate, Change Values

Fast: Silverlight 3, Reset, check only Set Axis Ranges, Create Chart, Add Series, 100 points, Populate, Change Values

 

Tip: Add the points more efficiently

Silverlight/WPF Charting is built around a model where any changes to the data are automatically shown on the screen. This is accomplished by detecting classes that implement the INotifyPropertyChanged interface and collections that implement the INotifyCollectionChanged interface and registering to find out about changes as they occur. This approach is incredibly easy for developers because it means all they have to touch is their own data classes - and Charting handles everything else! However, this system can be counterproductive in one scenario: starting with an empty collection and adding a bunch of data points all at once. By default, each new data point generates a change notification which prompts Charting to re-analyze the data, re-compute the axis properties, re-layout the visuals, etc.. It would be more efficient to add all the points at once and then send a single notification to Charting that its data has changed. Unfortunately, the otherwise handy ObservableCollection class doesn't offer a good way of doing this. Fortunately, it's pretty easy to add:

// Custom class adds an efficient AddRange method for adding many items at once
// without causing a CollectionChanged event for every item
public class AddRangeObservableCollection<T> : ObservableCollection<T>
{
    private bool _suppressOnCollectionChanged;

    public void AddRange(IEnumerable<T> items)
    {
        if (null == items)
        {
            throw new ArgumentNullException("items");
        }
        if (items.Any())
        {
            try
            {
                _suppressOnCollectionChanged = true;
                foreach (var item in items)
                {
                    Add(item);
                }
            }
            finally
            {
                _suppressOnCollectionChanged = false;
                OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
            }
        }
    }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (!_suppressOnCollectionChanged)
        {
            base.OnCollectionChanged(e);
        }
    }
}

Slow: Reset, uncheck everything, Create Chart, Add Series, 500 points, Populate

Fast: Reset, check only Efficient Collection, Create Chart, Add Series, 500 points, Populate

 

Tip: Disable the data change animations

Because people perceive changes better when they're able to see the change happening, Charting animates all value changes to the underlying data points. So instead of a bar in a bar chart suddenly getting longer when its bound data value changes, the bar smoothly animates from its old value to its new value. This approach has another benefit: it calls attention to the value that's changed in a way that an instantaneous jump wouldn't. However, animating value changes can take a toll when there are lots of changes happening at the same time or when there are a continuous stream of changes over a long time. In cases like these, it can be helpful to lessen the default duration of the animation (a half second) by lowering the value of the series's TransitionDuration property - all the way down to 0 if that's what it takes.

Slow: Silverlight 3, Reset, uncheck everything, Create Chart, Add Series, 100 points, Populate, Change Values

Fast: Silverlight 3, Reset, check only Zero Transition Duration, Create Chart, Add Series, 100 points, Populate, Change Values

 

Tip: Use a different platform or version

Though they offer basically identical APIs, Silverlight and WPF are implemented very differently under the covers - and what performs poorly on one platform may run quite well on the other. Even staying with the same platform, Silverlight 4 contains a number of improvements relative to Silverlight 3 (as does WPF 4 vs. WPF 3.5). Therefore, if you have the freedom to choose your target platform, a bit of prototyping early on may help to identify the best choice for your scenario.

Slow: Silverlight 3, Reset, uncheck everything, Create Chart, Add Series, 100 points, Populate, Change Values

Fast: WPF 3.5, Reset, uncheck everything, Create Chart, Add Series, 100 points, Populate, Change Values

Two birds, squared! [Silverlight/WPF Data Visualization Development Release 3 and a DataVisualizationDemos update]

We shipped the November 2009 release of the Silverlight Toolkit a little over a week ago and it includes a handful of improvements to the Data Visualization assembly. It also adds support for the new Silverlight 4 Beta! And while we were busy getting the October/November Toolkits out the door, the WPF team previewed WPF 4 along with the .NET 4 and Visual Studio 2010 Beta!

Which means there are now four platforms of interest to developers: Silverlight 3, Silverlight 4, WPF 3.5, and WPF 4. And the Silverlight/WPF Data Visualization assembly supports them all!

 

Silverlight/WPF Data Visualization Development Release 3

As with previous Data Visualization Development Releases, I've updated to the most recent Toolkit code. And like last time, the Silverlight Toolkit shipped most recently so the code in the new Development Release is identical to what just went out with the Silverlight 3/4 Toolkits. However, people using Data Visualization on WPF 3.5 or 4 can take advantage of the latest changes by updating to the binaries included with this Development Release or by compiling the corresponding code themselves.

[Click here to download the SilverlightWpfDataVisualization solution including complete source code and pre-compiled binaries for all four platforms.]

Notes:

  • This is the first release I know of that supports four different platforms with distinct implementations on each. While the code and XAML are 99+% identical across the platforms, each has at least one customization that makes it unique. [Bonus points for identifying them all! :) ]
  • Previously, there was a single Visual Studio 2008 SilverlightWpfDataVisualization.sln file for both Silverlight 3 and WPF 3.5. Because Silverlight 4 and WPF 4 use Visual Studio 2010, there's a new SilverlightWpfDataVisualization4.sln file for those two platforms. The two solutions (and the projects within) look and act exactly the same - they're separate because they compile with different tools and because separation lets people who haven't upgraded continue to use the VS 2008 solution.
  • I always strive for code that builds with no compile or code analysis warnings, and that's still the case when compiling for Silverlight 3, WPF 3.5, and Silverlight 4 (though the last is a bit of a cheat because code analysis doesn't work there yet). But the new .NET 4 tools include some improvements, and there were three new kinds of warnings when I first compiled for WPF 4. Two of them were easily addressed with trivial changes I already made, but the third requires a bit more (potentially destabilizing) work that was not done for this release: Warning 2 CA1062 : Microsoft.Design : In externally visible method 'Foo', validate parameter 'Bar' before using it. As it happens, there was already a work item for this task because we knew we weren't checking everywhere we should. So if you see this warning when compiling the WPF 4 assembly, please don't be alarmed!
  • Whereas it used to be fine to wrap platform-specific code in #if SILVERLIGHT blocks, that doesn't work anymore because there are now cross-version changes within each platform. Therefore, I've switched to the form #if !NO_FEATURE instead. It's usually best to avoid double-negatives, but their use here is a consequence of a deliberate decision. My goal is that, by default, the code tries to use every feature it supports and if the target platform doesn't implement something, there's a compile error. At which point it's easy to identify the problem and add the relevant #define to the project file to "turn off" the unsupported feature. This seem better to me than forcing developers to know all the relevant flags and use them to "turn on" features for each platform. Just another example of the pit of success, really... :)
  • WPF 4 includes the Visual State Manager classes in the framework, so the WPF 4 Data Visualization assembly no longer has a dependency on the WPF Toolkit!

 

DataVisualizationDemos on WPF 4

 

DataVisualizationDemos Sample Project Updated

The DataVisualizationDemos application is a collection of all the Data Visualization samples I've posted to my blog. Like the Data Visualization assembly itself, the demo application runs on Silverlight 3 and 4 as well as WPF 3.5 and 4 and shares the same code and XAML across all four platforms. Not only is it a convenient way to look at a variety of sample code, it also has links back to the relevant blog posts for more detail about each sample.

Click here to download the complete source code for the cross-platform DataVisualizationDemos sample application.

Notes:

  • I've followed the same dual-solution and #if approaches that I describe above.
  • Because WPF 4 now supports easing functions, the "Gelatin Sales" example on the "Charting Introduction" tab runs on that platform - as does the entire "Jelly Charting" demo. And boy, is it smooth on WPF! :)

 

With the release of Silverlight/WPF Data Visualization Development Release 3, it's easy for anyone to compile and run the Data Visualization assembly on any of Microsoft's four premier development platforms. So what are you waiting for? ;)